#pragma once

#include "qvector.h"
#include "qthread.h"

class QtCascade;

struct Group
{
	int start;
	int end;
	int parity;
};

inline bool operator==(Group a, Group b)
{
	return a.start == b.start && a.end == b.end;
}

inline bool operator!=(Group a, Group b)
{
	return !(a == b);
}

class MAlice : public QObject
{
	Q_OBJECT

public:
	MAlice(QObject* parent = 0);
	~MAlice();
	void setKeys(const QVector<uint>& ikeys);
	const QVector<uint>& keys() const;
	void correct(int loopCount, float errorRatio);

signals:
	void asyncBeginCorrect(int loopCount, int thisLoop);
	void sendGroup(const QVector<Group>& segments, int loopCount, int thisLoop);
	void sendPairty(int value, bool *completed);

private slots:
	void beginCorrect(int loopCount, int thisLoop);
	void receiveBinarySegment(int start, int end, bool *completed);

private:
	int calcParity(int start, int end);

private:
	float sep;
	QVector<uint> myKeys;
	QThread workThr;
	friend QtCascade;
};

struct BinaryCorrect
{
	int start;
	int end;
	int cstart;
	int cend;
};

class MBob : public QObject
{
	Q_OBJECT

public:
	MBob(QObject* parent = 0);
	~MBob();
	void setKeys(const QVector<uint>& ikeys);
	const QVector<uint>& keys() const;

signals:
	void sendBinarySegment(int start, int end, bool* completed);
	void sendBeginCorrect(int loopCount, int thisLoop);
	void finished();

private slots:
	void receiveGroup(const QVector<Group>& groups, int loopCount, int thisLoop);
	void receiveParity(int value, bool *completed);

private:
	void execCorrectOnce(const QVector<Group>& groups);
	int execBinaryCorrect(const Group& segment);
	int calcParity(int start, int end);
	QVector<Group> xor(const QVector<Group>& a, const QVector<Group>& b);
	void findFromHistory(int keyIndex, const Group& exclude, QVector<Group> &past);
	void flipKey(int index);

private:
	BinaryCorrect binary;
	QVector<uint> myKeys;
	QVector<QVector<Group>> history;
	QThread workThr;
	friend QtCascade;
};



